#include "EmisorDelta.h"

void EmisorDelta::CalcularHashesVarios()
{
    StreamBloqueante SBloq(this->RutaFile,std::ios::in | std::ios::binary);
    std::fstream& ArDelEMISOR = SBloq.stream() ;
    unsigned int NumeroDeChunk = 0;
    //std::cout << "Archivo del Emisor" << std::endl;
    while( ArDelEMISOR.good() )
    {
        //me voy desplazando como una ventana
        ArDelEMISOR.seekg(NumeroDeChunk);
        char buffer[TAM_PEDAZO+1];
        ArDelEMISOR.read ( buffer, TAM_PEDAZO );
        if ( ArDelEMISOR.gcount() == 0 ){break;}
        buffer[ArDelEMISOR.gcount()]='\0';
        std::string hexbuffer;
        BinToHex((uint8_t*)buffer,ArDelEMISOR.gcount(),hexbuffer);
        ADLER32 ad32( hexbuffer );
        std::string adthirty2 = ad32.hexdigest();
        PaqueteHashEmisor PdH( NumeroDeChunk ,adthirty2 );
        this->ListaRollingH.push_back(PdH);
        //std::cout << NumeroDeChunk << ")" << "size:"<< ArDelEMISOR.gcount() <<
        //            "|"<< buffer << "|"<< adthirty2 <<std::endl;
        NumeroDeChunk += 1;
    }
    //std::cout << "Cantidad de Chunks "<< (NumeroDeChunk)<< std::endl;
}


    //http://rsync.samba.org/tech_report/node4.html
    // Este es el cuco del tp
DatosTrasmitidos<Diferencial> EmisorDelta::compararConHashesDelReceptor(const DatosTrasmitidos<PaqueteHashReceptor>& HpRec)
{
    //Me abstrae de todo el problema del tratado de archivos
    LectorDeSegmento LectorSegm(this->RutaFile);
    //esto es lo que voy a devolver
    DatosTrasmitidos<Diferencial> HojaDeDiferenciales;
    //ESTOS son los hashes del emisor ( rolling )
    std::list<PaqueteHashEmisor>::const_iterator itEmisor = this->ListaRollingH.begin();

    //ESTOS son los hashes del receptor ( me los pasaron desde afuera ) ( MD5 y Rolling )
    std::list<PaqueteHashReceptor> ListaHashRec = HpRec.getDatos();
    std::list<PaqueteHashReceptor>::const_iterator itReceptor;
    //********************************************************
    // esto lo voy a usar para saber que pedazo leer del archivo del emisor
    // para emitirle al receptor
    unsigned int EMISORCurrentFileOffset = 0 ;
    unsigned int EMISORPreviousFileOffset = 0 ;
    unsigned int SaltearRollingHashesEmisor = 0;
    bool MATCH = false;
    //Voy a iterar sobre cada rolling hash del Emisor,
    //viendo si esta en la lista recibida del Receptor
    for ( ; itEmisor != this->ListaRollingH.end() ; itEmisor++ )
    {
        // If a match is found, the search is restarted at the end of the matched block.
        if ( SaltearRollingHashesEmisor != 0 )
        {
            SaltearRollingHashesEmisor-=1;
            continue;
        }
        MATCH = false;
        PaqueteHashEmisor Paquete_Emisor = *itEmisor ;

        //std::cout << "working :"<<Paquete_Emisor.numP << std::endl;
        for ( itReceptor = ListaHashRec.begin(); itReceptor != ListaHashRec.end(); ++itReceptor )
        {
            PaqueteHashReceptor Paquete_Receptor = *itReceptor ;
            if ( Paquete_Emisor.VerificacionDebil(Paquete_Receptor) )
            {
                /*std::cout << "Se entro en verificacion debil" << std::endl;
                std::cout << "numP: " << Paquete_Emisor.numP << std::endl;
                std::cout << "rolling Check " << Paquete_Receptor.ROLLINGCS << std::endl;
                std::cout << "Bloqueleido "<< BloqueEmisor << std::endl;
                std::cout << "StrongCheck "<< StrongChecksum << std::endl;
                std::cout << "MD5 recept " << Paquete_Receptor.MD5 << std::endl;*/
                //Verificacion fuerte
                if ( Paquete_Emisor.VerificacionFuerte(Paquete_Receptor,LectorSegm) )
                {
                    //std::cout << "Se entro en verificacion fuerte" << std::endl;
                    MATCH = true;
                    //std::cout << "match!:"<< Paquete_Emisor.numP << std::endl;
                    //if a match is found, EMISOR sends RECEPTOR the data in EMISOR FILE
                    //between the CurrentFileOffset and the PreviousFileOffset
                    //, followed by the INDEX OF THE BLOCK in REC FILE that matched.
                    std::string Segmento ="";
                    unsigned int Distancia = EMISORCurrentFileOffset-EMISORPreviousFileOffset;
                    if (Distancia != 0)
                    {
                        Segmento = LectorSegm.getDif(EMISORPreviousFileOffset
                                                    ,Distancia);
                        //std::cout << "diferencia)" << Segmento << std::endl;
                        //std::cout << "+++++++++++++++++++++" << std::endl;
                    }
                    Diferencial Dif(Segmento,Paquete_Receptor.getNumPaquete() );
                    HojaDeDiferenciales.agregarDato(Dif);
                    break;
                }
            }
        }
        if ( !MATCH )
        {
            //If no match is found at a given offset in the file,
            //the rolling checksum is updated to the next offset
            //and the search proceeds.
            EMISORCurrentFileOffset += 1;
            //std::cout << EMISORCurrentFileOffset << std::endl;
        }
        else
        {
            EMISORCurrentFileOffset += TAM_PEDAZO;
            EMISORPreviousFileOffset = EMISORCurrentFileOffset;
            SaltearRollingHashesEmisor = TAM_PEDAZO-1;
        }
    }
    //fundamental! quizas se terminaron de procesar los paquetes del emisor
    //pero me quedaron bytes al final
    EMISORCurrentFileOffset += LectorSegm.getFileSize() - EMISORCurrentFileOffset;
    /*std::cout << "dif: " << LectorSegm.getFileSize() - EMISORCurrentFileOffset << std::endl;
    std::cout << "saltearRh: " << SaltearRollingHashesEmisor << std::endl;
    std::cout << "current: "<< EMISORCurrentFileOffset << std::endl;
    std::cout << "previous: " << EMISORPreviousFileOffset << std::endl;
    std::cout << "size: " << LectorSegm.getFileSize() << std::endl;*/
    if ( EMISORCurrentFileOffset != EMISORPreviousFileOffset )
    {
        unsigned int Cant = EMISORCurrentFileOffset - EMISORPreviousFileOffset;
        //std::cout << "Volcando lo que quedo al final" << std::endl;
        std::string Segmento = LectorSegm.getDif(EMISORPreviousFileOffset,Cant);

        //std::cout << "resto)" << Segmento << std::endl;
        Diferencial Dif(Segmento,-1);
        HojaDeDiferenciales.agregarDato(Dif);
        //std::cout << "-----------------" << std::endl;
    }
    return HojaDeDiferenciales;
}
